import { Body, Controller, Delete, Get, Param, ParseIntPipe, Post, Put, Req, UploadedFile, UseInterceptors } from '@nestjs/common';
import { BaseController } from '../base/base.controller';
import { DbService } from '@app/db';
import { ChargingStation } from '@app/db/entities/ChargingStation';
import { FindOptionsWhere, In } from 'typeorm';
import { AddDto, PageDto, UpdateDto } from './dto';
import { DtoPipe } from '../pipes/dto/dto.pipe';
import { UploadService } from 'apps/common/src/upload/upload.service';
import { FileInterceptor } from '@nestjs/platform-express';
import { DeviceService } from '../device/device.service';
import { DictionaryService } from '../common/dictionary/dictionary.service';

@Controller('chargingStation')
export class ChargingStationController extends BaseController {
    constructor(
        private readonly db:DbService,
        private readonly upload:UploadService,
        private readonly device:DeviceService,
        private readonly dictionary:DictionaryService,
    ){
        super()
    }

    @Post('upload/pic')
    @UseInterceptors(FileInterceptor('pic'))
    async updateInfo(@UploadedFile() pic: Express.Multer.File, @Req() { memberId }) {
        const fileName = await this.upload.put(pic, 'station' + memberId)
        return this.successRes(fileName)
    }

    @Post('page')
    async page(@Body() dto:PageDto, @Req() { belong, member }) {

        let result:PaginationResult<ChargingStation> = {
            total : 0,
            rows : []
        }

        let where:FindOptionsWhere<ChargingStation> = {
            
        }

        if(belong == 1) {
            where.owner = member.tenantId
        }

        // if(dto.orderNo) {
        //     where.orderNo = dto.orderNo
        // }

        result.total = await this.db.chargingStation.count(where)

        if(result.total > 0) {
            result.rows = await this.db.chargingStation.pagination(dto.pageNo, dto.pageSize, where, {totalChargeAmount : false, totalChargeKwh : false, totalChargeTime : false}, {id : 'DESC'})

        }
        

        return this.successRes(result)

    }

    @Get('info/:id')
    async info(@Param('id', ParseIntPipe) id:number, @Req() { belong, member }) {
        if(isNaN(id) || id < 1) return
        const station = await this.db.chargingStation.findOne({id : id})
        if(belong == 1 && station.owner != member.tenantId) {
            return null
        }

        if(station.labels && station.labels.length > 0) {
            const labels = await this.dictionary.getItemCodeToNameByCategory('CHARGE_STATION_LABEL')
            station.labels.forEach((label, i) => {
                station.labels[i] = labels[label] as string
            })
        }

        return this.successRes(station)
    }

    @Post('add')
    async add(@Body(new DtoPipe({skipMissingProperties : false})) dto:AddDto, @Req() { memberId, belong, member }) {
        const data:KeyToValueType<ChargingStation> = {
            ...dto,
            createTime : this.utils.time(),
            creatorId : memberId
        }

        if(belong == 1) {
            data.owner = member.tenantId
        }


        if(data.pics && data.pics.length == 0) {
            delete data.pics
        }

        if(data.labels && data.labels.length == 0) {
            delete data.labels
        }


        const res = await this.db.chargingStation.insert(data)
        if(res && res.affectedRows > 0) {
            return this.successRes()
        }

        return this.failRes()
    }

    @Put('update/:id')
    async update(@Body(new DtoPipe({skipNullProperties : true})) dto:UpdateDto, @Param('id', ParseIntPipe) id:number, @Req() { member, belong }) {
        if(id <= 0) return


        let fields = Object.keys(dto) as (keyof ChargingStation)[]
        if(fields.length == 0) return
        fields.push('owner')
        const station = await this.db.chargingStation.findOne({id : id}, fields)
        if(!station || station.owner != member.tenantId) return

        let updateData:KeyToValueType<ChargingStation> = {}
        for(let k in station) {
            if(k in dto && station[k] != dto[k]) {
                updateData[k] = dto[k]
            }
        }

        const dropPics:string[] = []

        if(updateData.pics && station.pics) {
            station.pics.forEach(pic => {
                if(!updateData.pics.includes(pic)) {
                    dropPics.push(pic)
                }
            })
        }


        if(Object.keys(updateData).length == 0) return this.successRes()

        const res = await this.db.chargingStation.update({id : id}, updateData)
        if(res === 0) return this.failRes()

        if(dropPics.length > 0) {
            this.upload.delFiles(dropPics)
        }
        return this.successRes()
    }

    @Delete('delete/:id')
    async del(@Param('id', ParseIntPipe) id:number, @Req() { member, belong }) {
        if(id <= 0) return
        const station = await this.db.chargingStation.findOne({id}, ['owner', 'pics'])
        if(!station || station.owner != member.tenantId) return

        const r0 = await this.db.device.update({stationId : id}, {stationId : 0})
        const r = await this.db.chargingStation.delete({id : id})
        if(r == 0) {
            return this.failRes()
        }else {
            
            if(station.pics != null) {
                this.upload.delFiles(station.pics)
            }
            return this.successRes()
        }

    }


    @Post('push/setting')
    async pushSetting(@Body() ids:number[], @Req() { member, belong }) {
        if(ids.length == 0) return this.successRes()
        const stations = await this.db.chargingStation.find({id : ids.length == 1 ? ids[0] : In(ids)}, ['id', 'owner', 'fastPricing', 'slowPricing'])
        if(stations.length != ids.length) return this.successRes()
        const index = stations.findIndex(s => s.owner != member.tenantId)
        if(index >= 0) return this.successRes()

        stations.forEach(station => {

        })

        for(let i = 0; i < stations.length; i ++) {
            const station = stations[i]
            if(!station.slowPricing && !station.fastPricing) return this.failRes(station.id + '未设置收费标准')
            this.device.pushSettingToDeviceByStation(station)
        }

        return this.successRes()
        
    }
}
